﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Backend.JYD.Config.Watcher;

namespace Backend.JYD.Config
{
    /// <summary>
    /// 文件监视基类
    /// </summary>
    internal class FileWatcher
    {
        /// <summary>
        /// 文件系统监控器
        /// </summary>
        protected FileSystemWatcher _Watcher;

        /// <summary>
        /// 监控配置
        /// </summary>
        protected WatcherConfig _Config = null;

        ///// <summary>
        ///// 监视事件
        ///// </summary>
        //public FileSystemEventHandler _WatcherChanged;

        /// <summary>
        /// 监控变更执行事件
        /// </summary>
        public IWatchExecuter _WatchExecuter;

        /// <summary>
        /// 锁定（修改文件后的操作）
        /// </summary>
        private object _lockFile = new object();


        private static Dictionary<string, DateTime> WatcherExecuteTime = null;

        /// <summary>
        /// 
        /// </summary>
        public FileWatcher(WatcherConfig config, IWatchExecuter executer)
        {
            this.LoadConfig(config, executer);
        }

        private void LoadConfig(WatcherConfig config, IWatchExecuter executer)
        {
            this._Config = config;
            this._WatchExecuter = executer;
            if (WatcherExecuteTime == null)
                WatcherExecuteTime = new Dictionary<string, DateTime>();
        }

        #region 加载文件监视器

        /// <summary>
        /// 基类加载
        /// </summary>
        public void Init()
        {
            #region 初始化

            if (_Watcher != null)
            {
                _Watcher.Dispose();
                _Watcher = null;
            }

            if (this._Config == null)
                throw new Exception("config is null.");
            if (this._WatchExecuter == null)
                throw new Exception("watchexecuter is null");

            #region 开关拦截

            if (!this._Config.Enable) return;

            #endregion

            if (this._Config.WatcherType == WatcherConfig.TargetType.Folder)
            {
                _Watcher = new FileSystemWatcher(this._Config.Path);
            }
            else
            {
                _Watcher = new FileSystemWatcher(this._Config.Path, this._Config.FileName);
            }
            //this._WatcherChanged = new FileSystemEventHandler(Watcher_Changed);
            _Watcher.IncludeSubdirectories = this._Config.IncludeSubdirectories;
            _Watcher.Changed += new FileSystemEventHandler(Watcher_Changed);

            _Watcher.EnableRaisingEvents = true;

            #endregion
        }

        public void Stop()
        {
            if (_Watcher != null)
            {
                _Watcher.Dispose();
                _Watcher = null;
            }
        }
        #endregion

        #region 更新事件

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Watcher_Changed(object sender, FileSystemEventArgs e)
        {
            Thread.Sleep(100);

            lock (_lockFile)
            {
                DateTime lastModifyTime = File.GetLastWriteTime(e.FullPath); 
                DateTime prevModifyTime = DateTime.MinValue;
                lock (WatcherExecuteTime)
                {
                    if (WatcherExecuteTime.TryGetValue(e.FullPath.ToLower(), out prevModifyTime))
                    {
                        if (prevModifyTime < lastModifyTime)
                        {
                            WatcherExecuteTime[e.FullPath.ToLower()] = lastModifyTime;
                        }
                        else
                        {
                            return;
                        }
                    }
                    else
                    {
                        WatcherExecuteTime.Add(e.FullPath.ToLower(), lastModifyTime);
                    }
                }
                try
                {
                    this._WatchExecuter.ExeCute();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        #endregion
    }
}